import os
from loguru import logger
from astropy.io import fits
import numpy as np
import math
import ntpath
import subprocess
from astropy.io import fits
import numpy as np
import os
import matplotlib


from loguru import logger

matplotlib.use('AGG')


def d2hms(ra, dec, conv=0):
    """
    convert ra&dec in (degree, degree) to (hhmmss, ddmmss),
    or (hhmmss, ddmmss) to (degree, degree)
    Parameters:
    ra, dec:
       if (ra, dec) is in (deg, deg), float
       if in (hms, dms), string
    conv: 0 or 1
       0: (degree, degree) to (hhmmss, ddmmss)
       1: (hhmmss, ddmmss) to (degree, degree)
    Example:
    d2hms(1.0, 1.0, conv=0)
    d2hms(00:00:00.0, 00:00:00.0, conv=1)
    """
    if conv == 0:
        rah = ra / 15.0
        ram = (rah - int(rah)) * 60.0
        ras = (ram - int(ram)) * 60.0
        if rah < 10:
            rah = "0%d:" % int(rah)
        else:
            rah = "%d:" % int(rah)
        if ram < 10:
            ram = "0%d:" % int(ram)
        else:
            ram = "%d:" % int(ram)
        if ras < 10:
            ras = "0%.4f" % float(ras)
        else:
            ras = "%.4f" % float(ras)
        sra = rah + ram + ras
        decabs = abs(dec)
        dech = int(decabs)
        decm = (decabs - dech) * 60.0
        decs = (decm - int(decm)) * 60.0
        if dech < 10:
            dech = "0%d:" % int(dech)
        else:
            dech = "%d:" % int(dech)
        if decm < 10:
            decm = "0%d:" % int(decm)
        else:
            decm = "%d:" % int(decm)
        if decs < 10:
            decs = "0%.4f" % float(decs)
        else:
            decs = "%.4f" % float(decs)
        sdec = dech + decm + decs
        if dec < 0.0:
            sdec = "-" + sdec
        else:
            sdec = "+" + sdec
        return sra, sdec
    elif conv == 1:
        decSign = dec[0]
        sra = np.array(ra.split(":"), dtype=float)
        sdec = np.array(dec[1:].split(":"), dtype=float)
        sra = ((sra[-1] / 60.0 + sra[1]) / 60.0 + sra[0]) * 15.0
        if decSign == "-":
            sdec = -((sdec[-1] / 60.0 + sdec[1]) / 60.0 + abs(sdec[0]))
        elif decSign == "+":
            sdec = (sdec[-1] / 60.0 + sdec[1]) / 60.0 + sdec[0]
        else:
            raise ValueError("!!! Give a right dec value")
        return sra, sdec
    else:
        return None,None

def getkey(fullpath):
    try:
    #if(1==1):
        hdr= fits.getheader(fullpath)
        time = hdr['DATE']
        dates=time.split('T')[0]
        date = str(dates).replace(':','').replace('-','')
        if 'SERNO'in hdr.keys():
            if(int(date)<20230308):
                tid_dic={'25077':'mb', '25076':'my', '25078':'mr'}
            else:
                tid_dic={'25077':'mb', '25078':'my', '25076':'mr'}
            
            tid = tid_dic[str(hdr['SERNO'])]
        else:
            tid='mr'
        filterid=hdr['FILTER']
        objectid= hdr['OBJECT'] 
    except:
        filepath, filename = os.path.split(fullpath)
        tid, ftype,objectid, filterid, fileid = splitfilename(filename)
    return tid.replace(" ",""),objectid.replace(" ",""),filterid.replace(" ","")

def splitfilename(filename):
    '''
    将文件名按照特定的格式进行拆分，并返回对应的字段值
    参数：
        filename：文件名
    返回：
        cid：字段1
        type：字段2
        objectname：字段3
        filterid：字段4
        file_id：字段5
    '''
    # 将文件名按照"."进行分割，取第一个元素，再按照"_"进行分割
    namelist = filename.split('.')[0].split('_')
    # 将拆分后的字段值依次赋给对应的变量
    cid = namelist[0]
    type= namelist[1]
    objectname = namelist[2]
    filterid = namelist[3]
    file_id = namelist[4]
    # 返回字段值
    return cid,type, objectname, filterid, file_id


def hdr_edit_fits_new(filename):
    
    hdr = fits.getheader(filename)
    
    tgdic={'v':'b','u':'b','g':'y','r':'y','i':'r','z':'r'}
    filterid_dic={'u':'1','v':'2','g':'3','r':'4','i':'5','z':'6'}
    
    ira  =    float(hdr['TEL_RA'])
    idec  =   float(hdr['TEL_DEC'])
                     
    
    pscale = 0.429 
    
    if "DETECTOR" in hdr.keys():
        if(hdr['DETECTOR']=='E2V-CCD290'):
            pscale=0.286
            hdr['PIXSCAL1'] = pscale*hdr['HBIN']
            hdr['PIXSCAL2'] = pscale*hdr['VBIN']
            
            logger.info('ccd290')
    else:
        logger.info('andor')
        hdr['OBSERVAT']= 'GMG'
        hdr['OBSLON'] = 100.0313 #deg
        hdr['OBSLAT'] = 26.6974  #deg
        hdr['OBSALT'] = 3227     #deg
        hdr['DETECTOR']= 'PilCam'
        hdr['TELESCOP'] = 'Mephisto'
    

    filterid =hdr['FILTER'] 
    hdr['FILTID'] = filterid_dic[filterid]
    hdr['CHANNEL'] = tgdic[filterid]
     

    c =  hdr['NAXIS1']
    r =  hdr['NAXIS2']
    if not 'PIXSCAL1' in hdr.keys():
        hdr['PIXSCAL1'] = pscale*hdr['HBIN']
        hdr['PIXSCAL2'] =pscale*hdr['VBIN']
    if not 'PIXSIZE1' in hdr.keys():
        hdr['PIXSIZE1'] = 15*hdr['HBIN']
        hdr['PIXSIZE2'] = 15*hdr['VBIN']
    
    pscale_bin = pscale * hdr['HBIN']  # 计算图像的缩放因子，pscale 是像素比例尺，HBIN 是水平的 binning 因子
    hdr['EPOCH'] = 2000.0  # 指定观测历元为 2000.0
    hdr["CTYPE1"] = "RA---TAN"  # 指定第一坐标轴的类型为赤经，投影方式为切线投影
    hdr["CTYPE2"] = "DEC--TAN"  # 指定第二坐标轴的类型为赤纬，投影方式为切线投影
    hdr["EQUINOX"] = 2000.0  # 指定坐标系统的分点，为 J2000.0
    hdr["RADESYS"] = "ICRS"  # 指定天体坐标系统为国际天球参考系统（ICRS）
    hdr["CUNIT1"] = "deg"  # 指定第一坐标轴的单位为度
    hdr["CUNIT2"] = "deg"  # 指定第二坐标轴的单位为度
    hdr["CRVAL1"] = ira  # 指定参考点（图像中心）的赤经坐标
    hdr["CRVAL2"] = idec  # 指定参考点（图像中心）的赤纬坐标
    hdr["CRPIX1"] = int(c)/2  # 指定参考点在图像中的像素坐标（水平位置），一般为图像宽度的一半
    hdr["CRPIX2"] = int(r)/2  # 指定参考点在图像中的像素坐标（垂直位置），一般为图像高度的一半
    # hdr["SATURATE"] = np.min([65535.0, icountmax])  # （注释掉的行）指定图像的饱和度水平，通常为 65535 或传感器的最大计数值
    # 确定旋转矩阵
    hdr["CD1_1"] = -pscale_bin / 3600.0  # 指定转换矩阵中第一坐标轴的比例因子，将像素单位转换为角度单位
    hdr["CD1_2"] = 0.0  # 指定转换矩阵中第一坐标轴的非对角线元素，表示无旋转
    hdr["CD2_1"] = 0.0  # 指定转换矩阵中第二坐标轴的非对角线元素，表示无旋转
    hdr["CD2_2"] = +pscale_bin / 3600.0  # 指定转换矩阵中第二坐标轴的比例因子，将像素单位转换为角度单位

    img = fits.getdata(filename)  # 从指定的 FITS 文件中读取图像数据
    fits.writeto(filename, img, hdr, overwrite=True)  # 将图像数据和更新后的头部信息写回到同一个 FITS 文件中，允许覆盖
    
    return ira, idec

def mkdir(path):
    folder = os.path.exists(path)
    if not folder:  # 判断是否存在文件夹如果不存在则创建为文件夹
        try:
            os.makedirs(path)  # makedirs 创建文件时如果路径不存在会创建这个路径
        except Exception as e:
            logger.info(e)  


def get_filename_without_extension(file_path):
    """
    获取文件名（无扩展名）

    :param file_path: 文件路径
    :return: 文件名（无扩展名）
    """
    base_name = os.path.basename(file_path)  # 获取文件名（带扩展名）
    name_without_extension = os.path.splitext(base_name)[0]  # 移除扩展名
    return name_without_extension




def delete_file_if_exists(file_path):
    if os.path.exists(file_path):
        try:
            os.remove(file_path)
        except Exception as e:
            logger.info(f"{file_path} delete failed: {e}")
      


def astronet_comd(astrocomd):
    astroComdlist = astrocomd.split(" ")
    
    try:
        # 执行命令并设置超时时间为300秒
        logger.info(f"Executing command: {' '.join(astroComdlist)}")
        completed_process_astrocomd = subprocess.run(astroComdlist, timeout=300, shell=False, capture_output=True)         
        
        # 处理命令执行结果
        if completed_process_astrocomd.returncode == 0:
            logger.info(f"Command executed successfully: {completed_process_astrocomd.stdout.decode('utf-8')}")
        else:
            logger.error(f"Command failed with error: {completed_process_astrocomd.stderr.decode('utf-8')}")
            logger.error('XXXXXXXXXXXXXXX astro failed XXXXXXXXXXXXXXXXX')
            
    except subprocess.TimeoutExpired:
        logger.error("Command execution timed out after 300 seconds.")
    except Exception as e:
        logger.error(f"An error occurred: {str(e)}")
        
        
def sex_comd(isexComd,type_cmd=True):    
    sexComdlist=[]

    logger.info(isexComd)

    try:
        if type_cmd:
            os.system(isexComd)
        else:
        
            completed_process_isexcomd = subprocess.run(sexComdlist, timeout=3000, shell=False, capture_output=True,check=True)
            logger.info(completed_process_isexcomd)    
                         
        # 处理命令执行结果
            if completed_process_isexcomd.returncode == 0:
            
                logger.info(completed_process_isexcomd.stdout)
            else:
                logger.info('XXXXXXXXXXXXXXXXXSEXTRACTOR')
                logger.info(completed_process_isexcomd.stderr)
            
    except subprocess.CalledProcessError as e:
        logger.error("Command failed with return code"+ str(e.returncode))
        logger.error("Standard output:"+ str(e.stdout.decode()))
        logger.error("Standard error:"+ str(e.stderr.decode()))
        raise ValueError(str(e.stderr.decode()))
    
    except subprocess.TimeoutExpired:
        logger.info("Command sex_comd execution timed out.")  



def psf_comd(ipsfComd):
    ipsfComdlist=[]
    #os.system(ipsfComd)
    ipsfComdlist=ipsfComd.split(" ")
    objfilename = ipsfComdlist[1] 
     
    objfilename = ntpath.basename(objfilename)
    objfilename =objfilename.split('_sciimg')[0]+'.fits'
    logger.info('*****************psfcomd************'+ objfilename)
    logger.info(ipsfComdlist)
    try:
        # 执行命令并设置超时时间为10秒
        logger.info('Command completed: ' + ' '.join(ipsfComdlist))
        
        
        completed_process_ipsfcomd = subprocess.run(ipsfComdlist, timeout=300*24, shell=False, capture_output=True,check=True)
        logger.info(completed_process_ipsfcomd)    
        logger.info(completed_process_ipsfcomd.stdout)
        logger.info('Return code: ' + str(completed_process_ipsfcomd.returncode))
        # 处理命令执行结果
        if completed_process_ipsfcomd.returncode == 0:
            logger.info('psf command has been processed successfully')
            logger.info('Standard output: ' + completed_process_ipsfcomd.stdout.decode())
            
        else:
            logger.info('psf command may not been processed successfully')
            logger.info(completed_process_ipsfcomd.stderr)
    except subprocess.CalledProcessError as e:
        logger.error("Command failed with return code"+ str(e.returncode))
        logger.error("Standard output:"+ str(e.stdout.decode()))
        logger.error("Standard error:"+ str(e.stderr.decode()))
        raise ValueError(str(e.stderr.decode()))
    
    except subprocess.TimeoutExpired:
        logger.info("Command psf_comd execution timed out.")
        return None, None



def ref_expt_select(confdir,filterid,expti,limmag_txt='limmag_mpilot.txt'):
    
    limmag_txt = os.path.join(confdir , limmag_txt)
     

    limmag_data = np.loadtxt(limmag_txt,skiprows = 1)
    filter_dic = {'u':1,'v':2,'g':3,'r':4,'i':5,'z':6}

    col = filter_dic[filterid]
    mag = limmag_data[:,col]
    exptime = np.array(limmag_data[:,0],dtype=float)

    maglim_dic = dict(zip(exptime,mag))
    idx = abs(exptime - expti).argmin()
    maglim_max = maglim_dic[exptime[idx]]
    maglim_max = math.ceil(maglim_max )
    logger.info(f'the exptime is {exptime[idx]}')
    logger.info(f'the maglim_max is {maglim_max}')

    return maglim_max


def run_scamp_commands(ildacn, refCatn, scampComd, scampConf, scampConf2, type_cmd=True):
    iscampComd = scampComd % (ildacn, scampConf, refCatn)
    logger.info(f"first: {iscampComd}")
    if type_cmd:
        os.system(iscampComd)
    else:
        scamp_comd(iscampComd)

    ihead = ildacn[:-4] + "head"
    ihead1 = ildacn[:-4] + "ahead"
    os.system(f"mv {ihead} {ihead1}")

    iscampComd2 = scampComd % (ildacn, scampConf2, refCatn)
    logger.info(f"second: {iscampComd2}")
    if type_cmd:
        os.system(iscampComd2)
    else:
        scamp_comd(iscampComd2)
    
    return ildacn[:-4] + "head"

### FITS 头信息更新函数

def scamp_comd(scampcomd):
     
    iscampComdlist=[]
    iscampComdlist=scampcomd.split(" ")
    logger.info(iscampComdlist)
    try:
        # 执行命令并设置超时时间为10秒
        completed_process_scampcomd = subprocess.run(iscampComdlist, timeout=300, shell=False, capture_output=True)
        #logger.info(iscampComdlist)           
        # 处理命令执行结果
        if completed_process_scampcomd.returncode == 0:
           
            logger.info(completed_process_scampcomd.stdout)
        else:
            logger.info(completed_process_scampcomd.stderr)
            logger.info('XXXXXXXXXXXXXXXscamp failedXXXXXXXXXXXXXXXX')
    
    except subprocess.TimeoutExpired:
        logger.info("Command scamp_comd execution timed out.")
        return None, None
